﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockCommon.baseclass;
using StockCommon.data;
using StockCommon;
using Utilities;
using StockImport.dataimport.common;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data;
using System.Collections;
using StockCommon.Calendar;
using StockCommon.TaskLog;
using StockImport.dataimport.tse.sb;

namespace StockImport.dataimport.otc.sb
{
    public abstract class SB_Import_Common:DBAccess
    {
        
        protected abstract TwnStockMarketType getMarket();
        protected abstract void createLog(DateTime date);
        protected abstract String getStorePath(DateTime date);
        public abstract bool hasSourceData(DateTime date);
        protected abstract int updateFromFile_internal(string code, DateTime date, string fileName, Guid taskId);
        protected abstract Guid getObjectId();
        protected abstract int update_internal(DateTime date, Boolean deleteOld);
        protected bool isTaskCreated(DateTime date)
        {
            String pat = @"select COUNT(*) as c from StockIndex where  StockIndex.市場='{0}'
                                      and StockIndex.代號 in (select SBDataTask.StockCode from SBDataTask
                                      where  SBDataTask.日期='{1}' )";
            String sql = String.Format(pat, EnumUtils.GetStringValue(getMarket()), DateUtils.toShortDateFormat(date));
            int c=getContext().ExecuteQuery<int>(sql).FirstOrDefault();
            return (c>0);
        }
        /**********************************************************************************************
         * 其實本來應該是用不到的,但是因為之前的otc都是抓下來就好了
         * 並沒有實際的task.因此在更新舊的時候必須要處理
         * *********************************************************************************************/
        protected void prepareTask(DateTime date)
        {
            //找出是否有已經create的了
            if (isTaskCreated(date))
                return;
            List<String> codes=StockDailyIndexServices.getTradeStockCode(date,getMarket());
            SB_Fetcher_Common.createTask(codes, date, getMarket());
        }
        public class RecordCount
        {
            public String code { get; set; }
            public int  count { get; set; }
        }
        protected Dictionary<String, RecordCount> recordCountOfDay=null;
        protected void LoadRecordOnDay(DateTime date)
        {
            String pat = "select distinct StockCode as code, COUNT(*) as count from SBDetails where SBDetails.日期='{0}' group by StockCode";
            String sql=String.Format(pat, DateUtils.toShortDateFormat(date));
            recordCountOfDay=getContext().ExecuteQuery<RecordCount>(sql).ToDictionary(x => x.code);
        }
        public void Update(DateTime date,bool deleteOld=false)
        {
         
            if (CalenderHelper.isWorkDay(date) == false)
                return;
            if (hasSourceData(date) == false)
                return;
            LoadRecordOnDay(date);
            StockCommon.ObjectExecLog log = ObjectExecServices.getExecLog(getObjectId(), "imp", date);
            if (ObjectExecServices.islogComplete(log))
            {
                if (deleteOld == false)
                return;
            }
            //是否要更新本日已經ok?-->不好 
            prepareTask(date);
            try
            {
                int c = update_internal(date,deleteOld);
                     log.status =(int) LogStatus.sUpdated;
                if (c > 0)
                    log.result = (int)LogResult.rComplete;
            }
            catch (Exception e)
            {
                log.result = (int)LogResult.rDataError;
            }
            updateSummary(date);
            ObjectExecServices.updateExecLog(log);

        }
        public void updateLog()
        {
            List<DateTime> dts = getContext().ExecuteQuery<DateTime>("select distinct 日期 from SBDetails order by 日期").ToList<DateTime>();
            foreach (DateTime dt in dts)
            {
                updateLog(dt);
            }
        }
        public void updateLog(DateTime date)
        {
            if (CalenderHelper.isWorkDay(date) == false)
                return;


            String m=EnumUtils.GetStringValue(getMarket());
            StockCommon.ObjectExecLog log = ObjectExecServices.getExecLog(getObjectId(), "imp", date);
            if (ObjectExecServices.islogComplete(log))
                return;

            String sql=String.Format("select distinct SBDetails.StockCode from SBDetails  with (NOLOCK) where SBDetails.日期='{0}'", DateUtils.toShortDateFormat(date));
            List<String> codes=getContext().ExecuteQuery<String>(sql).ToList();
            HashSet<String> marketcodes=StockCodeManager.filterForMarket(codes, getMarket());
            if (marketcodes.Count > 0)
            {
                log.status =(int)LogStatus.sUpdated;
                log.result=(int)LogResult.rComplete;
                System.Diagnostics.Debug.WriteLine("更新log " + DateUtils.toShortDateFormat(date)+" "+ EnumUtils.GetStringValue(getMarket()) + "家數:" + marketcodes.Count);
            }
            else
            {
                log.status =(int)LogStatus.sUpdated;
                log.result=(int)LogResult.rNoData;
            }
            ObjectExecServices.updateExecLog(log);
        }

        protected SBDataTask getTask(string code, DateTime date)
        {
            StockDataClassesDataContext context = getContext();
            SBDataTask task = (from t in context.SBDataTasks where (t.日期 == date && t.StockCode == code) select t).FirstOrDefault<SBDataTask>();
            return task;
        }
        protected void doDeleteOld(DateTime date)
        {
            if (hasSourceData(date) == false)
                return;
            var codes=StockDailyIndexServices.getTradeStockCode(date, getMarket());
            foreach (String code in codes)
            {
                doDeleteOld(code, date);
            }
        }
        protected void doDeleteOld(String code, DateTime date)
        {
            if(recordCountOfDay.ContainsKey(code)==false)
                return;
            if (recordCountOfDay[code].count == 0)
                return;

            String sql;
            String ds = DateUtils.toShortDateFormat(date);
            String pat2 = "delete from SBDetails where  StockCode='{0}' and 日期='{1}'  ";
            sql = String.Format(pat2, code, ds);
            getContext().ExecuteCommand(sql);
            //--->UpdateTask
            String pat3 = "update SBDataTask set state = {3}  where SBDataTask.StockCode='{0}' and SBDataTask.日期='{1}' and SBDataTask.state={2}  ";
            sql = String.Format(pat3, code,ds, (int)SBTaskState.完成, (int)SBTaskState.已抓取);
            getContext().ExecuteCommand(sql);
        }
        public class SBSummary_Simple
        {
            public DateTime 日期 {get;set;}
            public String  StockCode { get; set; }
            public Guid instId { get; set; }
            public String 機構名稱 {get;set;}
            public int 當日總買  { get; set; }
            public int 當日總賣 { get; set; }
            public int 交易次數 { get; set; }
            public int 淨量 { get; set; }
        }

        public void updateSummary()
        {
            String sql = "select distinct 日期 from SBDetails order by 日期";
            List<DateTime> ll=getContext().ExecuteQuery<DateTime>(sql).ToList();
            foreach (DateTime dt in ll)
            {
                updateSummary(dt);
            }
        }
        public void updateSummary(DateTime date)
        {
            date = DateUtils.getDateOnly(date);
            String market = EnumUtils.GetStringValue(getMarket());
            String sql = String.Format(" select COUNT(*) as c from StockIndex with (NOLOCK) where 市場='{0}' and 代號 in (select distinct StockCode from SBDetails where SBDetails.日期='{1}')  ", market,DateUtils.toShortDateFormat(date));
            int c = getContext().ExecuteQuery<int>(sql).FirstOrDefault();

            var context = getContext();
            var rec=(from l in context.SBDetailsLogs where l.日期 == date && l.市場 == market select l).FirstOrDefault();
            if (rec != null)
            {
                if (rec.股票家數 == c)
                    return;
                rec.股票家數 = c;
            }
            else
            {
                rec = new SBDetailsLog();
                rec.日期 = date;
                rec.市場 = market;
                rec.股票家數 = c;
                context.SBDetailsLogs.InsertOnSubmit(rec);
             }
            context.SubmitChanges();
        }
        protected Boolean updateFromFile(String fileName, String code, DateTime date, Boolean deleteOLD)
        {
            SBDataTask task = getTask(code, date);
            if (task == null)
            {
                //因為資料筆數可能為0 因此就找不到task了
                int ec=StockDailyIndexServices.getTradeCount(code, date);
                if (ec <= 0)
                    return true;
                throw new Exception("意外的錯誤,不知道為啥沒有Task");
            }
            if (task.state.Equals((int)SBTaskState.完成))
            {
                if(deleteOLD==false)
                return true;
            }
            doDeleteOld(code, date);
            System.Diagnostics.Debug.WriteLine("Process:" + code + " \t" + fileName);
            int c = updateFromFile_internal(code, date, fileName, task.SBId);
            System.Diagnostics.Debug.WriteLine("" + c + "筆");
            if (c >= 0)
            {
                updateTaskState(code, date, SBTaskState.完成);
                return true;
            }
            else
            {
                updateTaskState(code, date, SBTaskState.匯入錯誤);
                return false;
            }
        }

        protected  void updateTaskState(string code, DateTime date, SBTaskState state)
        {
            StockDataClassesDataContext context = LinqAgent.getContext();
            SBDataTask task = (from sb in context.SBDataTasks where (sb.StockCode == code && sb.日期 == date) select sb).FirstOrDefault<SBDataTask>();
            task.state = (int)state;
            context.SubmitChanges();
        }

        protected void performInsert(String code, DateTime date, Guid taskId, List<SBDetail> details)
        {
            StockDataClassesDataContext context = getContext();
            context.Connection.Open();
            DbTransaction transaction = context.Connection.BeginTransaction();
            DbCommand cmd = context.Connection.CreateCommand();

            cmd.Transaction = transaction;
            cmd.CommandText = "Insert into SBDetails ( taskId,seq,instId,price,buy,sell ,日期,StockCode) values (@taskId,@seq,@instId,@price,@buy,@sell ,@date,@stockCode)";
            DbParameter taskIdP = new SqlParameter("@taskId", DbType.Guid);
            DbParameter seqP = new SqlParameter("@seq", DbType.Int32);
            DbParameter instIdP = new SqlParameter("@instId", DbType.Guid);
            DbParameter priceP = new SqlParameter("@price", DbType.Decimal);
            DbParameter buyP = new SqlParameter("@buy", DbType.Int32);
            DbParameter sellP = new SqlParameter("@sell", DbType.Int32);

            DbParameter 日期P = new SqlParameter("@date", DbType.Date);
            DbParameter stockCodeP = new SqlParameter("@stockCode", DbType.String);

            cmd.Parameters.Add(taskIdP);
            cmd.Parameters.Add(seqP);
            cmd.Parameters.Add(instIdP);
            cmd.Parameters.Add(priceP);
            cmd.Parameters.Add(buyP);
            cmd.Parameters.Add(sellP);
            cmd.Parameters.Add(日期P);
            cmd.Parameters.Add(stockCodeP);

            cmd.Parameters[0].Value = taskId;
            cmd.Parameters[6].Value = date;
            cmd.Parameters[7].Value = code;

            foreach (SBDetail sb in details)
            {
                cmd.Parameters[1].Value = sb.seq;
                cmd.Parameters[2].Value = sb.instId;
                cmd.Parameters[3].Value = sb.price;
                cmd.Parameters[4].Value = sb.buy;
                cmd.Parameters[5].Value = sb.sell;

                cmd.ExecuteNonQuery();
            }

            transaction.Commit();
            cmd.Dispose();
            transaction.Dispose();
            context.Connection.Close();
        }

    }
}
